
#ifdef  USE_LIBUV
#include "uv.h"
#include "../core/Application.h"

#include "TcpServer.h"
#include "TcpSocket.h"


namespace LuaGui {
	static void on_tcp_server_close_cb(uv_handle_t* handle)
	{
		TcpServer* server = (TcpServer*)handle->data;
		if (server == nullptr) return;
		delete server;
	}

	static void on_tcp_server_new_connection_cb(uv_stream_t* svr_stream, int status)
	{
		if (status < 0) { // error!
			GetApplication()->Error("on_tcp_server_new_connection_cb: " + std::string(uv_strerror(status)));
			return;
		}

		TcpServer* server = (TcpServer*)svr_stream->data;
		if (server == nullptr)
		{
			return;
		}

		TcpSocket* socket = new TcpSocket;
		socket->SetServerUID(server->GetUID());
		if (0 != uv_accept(svr_stream, socket->GetUVStream()))
		{
			GetApplication()->Error("on_tcp_server_new_connection_cb: uv_accept failed");
			delete socket;
			return;
		}

		CallLuaGlobalFunction("__on_net__", "OnNetConnection", socket->GetUID(), socket->GetServerUID());
		GetApplication()->Debug("client connect: ip = " + socket->GetPeerIp() + " port = " + std::to_string(socket->GetPeerPort()));
		socket->OnRecv();
	}

	std::unordered_map<uint64_t, TcpServer*> TcpServer::s_tcp_servers;
	TcpServer::TcpServer()
	{
		m_uv_tcp = new uv_tcp_t;
		m_uv_tcp->data = this;
		uv_tcp_init(uv_default_loop(), m_uv_tcp);
		s_tcp_servers[GetUID()] = this;
	}

	TcpServer::~TcpServer()
	{
		delete m_uv_tcp;
		s_tcp_servers.erase(GetUID());
	}

	TcpServer* TcpServer::GetTcpServerByUID(uint64_t uid)
	{
		std::unordered_map<uint64_t, TcpServer*>::iterator it = s_tcp_servers.find(uid);
		if (it == s_tcp_servers.end()) return nullptr;
		return it->second;
	}

	// start tcp server
	int TcpServer::Start(std::string ip, unsigned int port)
	{
		sockaddr_in addr;
		uv_ip4_addr(ip.c_str(), port, &addr);
		uv_tcp_bind(m_uv_tcp, (const struct sockaddr*)&addr, 0);

		int errcode = uv_listen((uv_stream_t*)m_uv_tcp, 10, on_tcp_server_new_connection_cb);

		if (errcode != 0) {
			GetApplication()->Error("on_tcp_server_new_connection_cb: " + std::string(uv_strerror(errcode)));
		}

		return errcode;
	}

	void TcpServer::Stop()
	{
		uv_close((uv_handle_t*)m_uv_tcp, on_tcp_server_close_cb);
	}
}

#endif //  USE_LIBUV


